package com.jichangxiu.framework.entity.bo;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.jichangxiu.common.constant.Constants;
import com.jichangxiu.framework.utils.DynamicUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.transaction.Transaction;
import org.springframework.jdbc.datasource.DataSourceUtils;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Slf4j
public class DynamicTransaction implements Transaction {

    private final DataSource dataSource;

    private Connection mainConnection;

    private String mainDatabaseIdentification;

    private ConcurrentMap<String, Connection> otherConnectionMap;

    private boolean isConnectionTransactional;

    private boolean autoCommit;

    public DynamicTransaction(DataSource dataSource) {
        if (ObjectUtil.isNull(dataSource))
            throw new RuntimeException("【DynamicTransaction】数据源为空");
        this.dataSource = dataSource;
        otherConnectionMap = new ConcurrentHashMap<>();
        mainDatabaseIdentification = DynamicUtils.currentSource();
    }

    @Override
    public Connection getConnection() throws SQLException {
        String currentSource = DynamicUtils.currentSource();
        if (StrUtil.isEmpty(currentSource))
            currentSource = Constants.DEFAULT_DATA_SOURCE;
        if (currentSource.equals(mainDatabaseIdentification)) {
            if (mainConnection != null)
                return mainConnection;
            else {
                openMainConnection();
                mainDatabaseIdentification = currentSource;
                return mainConnection;
            }
        } else {
            if (!otherConnectionMap.containsKey(currentSource)) {
                try {
                    Connection conn = dataSource.getConnection();
                    otherConnectionMap.put(currentSource, conn);
                } catch (SQLException ex) {
                    throw new RuntimeException("【DynamicTransaction】无法获取JDBC连接", ex);
                }
            }
            return otherConnectionMap.get(currentSource);
        }
    }

    private void openMainConnection() throws SQLException {
        this.mainConnection = DataSourceUtils.getConnection(this.dataSource);
        this.autoCommit = this.mainConnection.getAutoCommit();
        this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.mainConnection, this.dataSource);
        if (log.isDebugEnabled())
            log.debug("【DynamicTransaction】JDBC连接【" + this.mainConnection + "】将" + (this.isConnectionTransactional ? "" : "不") + "会有 Spring 管理");
    }

    @Override
    public void commit() throws SQLException {
        if (this.mainConnection != null && !this.isConnectionTransactional && !this.autoCommit) {
            if (log.isDebugEnabled())
                log.debug("【DynamicTransaction】提交JDBC连接【" + this.mainConnection + "】");
            this.mainConnection.commit();
            for (Connection connection : otherConnectionMap.values())
                connection.commit();
        }
    }

    @Override
    public void rollback() throws SQLException {
        if (this.mainConnection != null && !this.isConnectionTransactional && !this.autoCommit) {
            if (log.isDebugEnabled())
                log.debug("【DynamicTransaction】回滚JDBC连接【" + this.mainConnection + "】");
            this.mainConnection.rollback();
            for (Connection connection : otherConnectionMap.values())
                connection.rollback();
        }
    }

    @Override
    public void close() throws SQLException {
        DataSourceUtils.releaseConnection(this.mainConnection, this.dataSource);
        for (Connection connection : otherConnectionMap.values())
            DataSourceUtils.releaseConnection(connection, this.dataSource);
    }

    @Override
    public Integer getTimeout() throws SQLException {
        return null;
    }

}
